import React = require("react");
import { IService, ServiceConstructor, ValueStore } from "maishu-chitu";
import { PageContext, Application, Page } from "maishu-chitu-react";
import { LocalService } from "../../mobile/services/localService";
import { MemberService } from "../../mobile/services/memberService";
import { ComponentInfo } from "./component";
import { MasterPageContext } from "maishu-jueying";
import { MasterPage } from "./master-page";
import { ADMIN_APP } from "common";
import { errorHandle } from "../../mobile/error-handle";
import { contextName } from "json!websiteConfig";

export function createService<T extends IService>(type?: ServiceConstructor<T>): T {
    let service = new type();
    //TODO: 处理错误
    service.error.add((sender, error) => {
        // alert({ title: "错误", message: error.message });
        errorHandle(error)
    })

    return service;
}

let clientFiles = new ValueStore<string[]>([]);
let localService = createService(LocalService);
localService.clientFiles().then(value => {
    console.assert(value != null);
    clientFiles.value = value;
})

export class BaseComponent<P, S> extends React.Component<P, S> {
    app: Application;
    memberService: MemberService;
    masterPage: MasterPage;
    page: Page;

    static componentInfos: ComponentInfo[];
    // componentCreated = Callbacks<BaseComponent<P, S>, React.Component<P, S>>();

    constructor(props) {
        super(props)

        let render = this.render;
        console.assert(render != null);
        this.render = () => {
            return <MasterPageContext.Consumer>
                {args => {
                    if (this.masterPage == null) {
                        this.masterPage = args.master as MasterPage;
                        this.memberService = this.createService(MemberService);
                        this.masterPage.getStyleColor().then(color => {
                            this.loadStyle(color);
                        })
                        this.masterPage.style.add(color => { this.loadStyle(color) });
                    }
                    console.assert(this.masterPage != null);
                    return <PageContext.Consumer>
                        {args => {
                            if (args.page) {
                                this.app = args.page.app;
                                this.page = args.page;
                            }

                            return render.apply(this);
                        }}
                    </PageContext.Consumer>
                }}
            </MasterPageContext.Consumer>
        }

    }

    async getComponentPaths() {
        if (BaseComponent.componentInfos != null && BaseComponent.componentInfos.length > 0)
            return BaseComponent.componentInfos;

        BaseComponent.componentInfos = await localService.getComponentInfos();
        return BaseComponent.componentInfos;
    }


    get isRuntime(): boolean {
        return window[ADMIN_APP] == null;
    }

    static get isDesigntime(): boolean {
        return window[ADMIN_APP] != null;
    }

    createService<T extends IService>(type?: ServiceConstructor<T>): T {
        return createService(type);
    }

    async loadStyle(color?: StyleColor) {
        color = color || "default";
        // clientFiles.attach(async (files) => {
        let files = clientFiles.value;
        let componentPaths = await this.getComponentPaths();
        let componentPath = componentPaths.filter(o => o.name == this.constructor.name)[0];
        console.assert(componentPath != null);
        let path = componentPath.path;
        if (path.endsWith(".js")) {
            path = path.substr(0, path.length - 3);
        }

        let lessPath = `${path}.less`;
        if (files.indexOf(lessPath) >= 0) {
            BaseComponent.loadLessFile(this, color, lessPath);
        }
        // })
    }

    static async loadLessFile(component: string, color: StyleColor, path: string)
    static async loadLessFile(component: React.Component, color: StyleColor, path: string)
    static async loadLessFile(componentOrName: React.Component | string, color: StyleColor, path: string) {
        color = color == null ? "default" : color;
        var typeName: string;
        if (typeof componentOrName == "string") {
            typeName = componentOrName;
        }
        else {
            typeName = componentOrName.constructor.name;
            typeName = typeName.replace('Control', '');
            typeName = typeName[0].toLowerCase() + typeName.substr(1);
        }

        let styleAttrName = "data-name";
        let style = document.head.querySelector(`style[${styleAttrName}="${typeName}"]`) as HTMLStyleElement;
        if (!style) {
            style = document.createElement('style');
            style.type = 'text/css';
            style.setAttribute(styleAttrName, typeName);
            document.head.appendChild(style);
        }

        if (color == style.getAttribute('color')) {
            return;
        }

        style.setAttribute('color', color);

        let contexts = requirejs.exec("contexts");
        let context: RequireContext = contexts[contextName];
        if (context != null && context.config.baseUrl != null) {
            path = context.config.baseUrl + path;
        }
        let lessText: string;
        lessText = `@import "${path}";`;
        if (color != 'default') {
            if (context != null && context.config.baseUrl != null)
                lessText = lessText + `@import "${context.config.baseUrl}components/style/colors/${color}.less";`;
            else
                lessText = lessText + `@import "components/style/colors/${color}.less";`;
        }

        import("lessc").then(lessc => {
            let parser = new lessc.Parser(window['less']);
            parser.parse(lessText, (err, tree) => {
                if (err) {
                    console.error(err);
                    return;
                }

                style.innerHTML = tree.toCSS();
            })
        })

    }

}

